dojo.provide("miaigo.model.Game");

dojo.require("miaigo.model.Move");
dojo.require("miaigo.model.MoveTree");
dojo.require("miaigo.model.BoardState");

dojo.declare(
    "miaigo.model.Game",
    null,
    {
	// A GameInfo object
	_gameInfo: null,

	// move tree (miaigo.model.MoveTree)
	_moveTree: null,

	getGameInfo: function(/* String */key)
	{
	    if (!this._gameInfo)
	    {
		this._gameInfo = this.buildGameInfo();
	    }

	    if (this._gameInfo)
	    {
		return this._gameInfo[key];
	    }

	    return null;
	},

	getTrunk: function()
	{
	    return this._moveTree;
	},

	buildMoveTree: function()
	{
	    this._moveTree = this._buildMoveTreeFromNode(this.rootNode(), null);
	},

	// return: miaigo.model.MoveTree
	_buildMoveTreeFromNode: function(
	    /* miaigo.model.Node */rootNode,
	    /* miaigo.model.Move */ownerMove
	)
	{
	    var tree = new miaigo.model.MoveTree( {owner: ownerMove} );
	    var baseState = null;
	    if (ownerMove)
	    {
		baseState = ownerMove.getBoardState();
	    }
	    else
	    {
		baseState = new miaigo.model.BoardState(this.getGameInfo("boardSize"));
	    }

	    var node = rootNode;

	    while (node)
	    {
		var move = null;
		if (node.isMove())
		{
		    move = new miaigo.model.Move
		    (
			{
			    srcNode: node,
			    baseState: baseState
			}
		    );

		    if (move.getError())
		    {
			console.error(move.getError());
			return null;
		    }

		    tree.addMove(move);
		    baseState = move.getBoardState();
		}
		
		var nextNodes = this.nextNode(node);

		if (nextNodes.length > 1 && move)
		{
		    for (var i=1; i<nextNodes.length; i++)
		    {
			var subTree = this._buildMoveTreeFromNode(nextNodes[i], move);
			move.addAlteration(subTree);
		    }
		}
		
		node = nextNodes[0];
	    }

	    return tree;
	},

	// Overrode to implement
	rootNode: function()
	{
	    // Return:
	    //   The root node
	},

	// Override to implement
	nextNode: function(/* miaigo.model.Node */refNode)
	{
	    // Summary:
	    //   Find the next node(s) of given node (refNode).
	    // Return:
	    //   An array of nodes.
	    //     Array length is 0 means no next node.
	    //     Array length is 1 means only one next node (no variation).
	    //     Array length greater than 1 means with variations. In this
	    //   case, [0] is the node on trunk, the others are variations.
	},

	// Override to implement
	buildGameInfo: function()
	{
	    // Summary:
	    // return a map
	}
    });